import struct
import socket
import time
from datetime import datetime
import random


# global variables
# TARGET_IP = '127.0.0.1'
# TARGET_PORT = 7777
TARGET_IP = '192.168.50.107'
TARGET_PORT = 6000

# Bind the socket to a specific IP address (e.g., IP of eth0, say 192.168.1.100)
LOCAL_IP = '192.168.50.109'  # The IP of the network interface you want to use
LOCAL_PORT = 0  # 0 means the OS will choose an available port for binding


SEND_INTERVAL = 1  # udp send interval(in ms)
SEND_SUM = 10000   # udp send number

# 1277 = 1265+4+8
REDUNDANT_DATA_LEN = 1265

UDP_SEND_RATE = 256#udp send rate (in KB/s)



def calculate_send_interval(rate_kb_per_s, packet_size_bytes):
    """
    计算发送间隔，以毫秒为单位
    :param rate_kb_per_s: 发送速率 (单位KB/s)
    :param packet_size_bytes: 每个UDP包的大小 (单位字节)
    :return: 发送间隔 (单位毫秒)
    """
    # 转换为字节单位
    rate_bytes_per_s = rate_kb_per_s * 1024
    
    # 计算每秒发送的包数
    packets_per_second = rate_bytes_per_s / packet_size_bytes
    
    # 计算每个包的发送间隔（秒）
    send_interval_seconds = 1 / packets_per_second
    
    # 转换为毫秒
    send_interval_ms = send_interval_seconds * 1000
    print(f"udp sned interval = {send_interval_ms}")
    time.sleep(1)
    
    return send_interval_ms


def gen_wrong_frame(frame_number):
    """
    sim wrong frame seq
    """
    random_int = random.randint(0,frame_number)
    random_float = random.random()
    if random_float < 0.99:
        return frame_number
    else:
        return random_int



def introduce_single_bit_errors(data: bytes, error_count: int) -> bytes:
    """
    在随机位置翻转单个bit
    :param data: 原始字节数据 (长度需 >= error_count)
    :param error_count: 要注入的错误bit数量
    :return: 包含错误的字节数据
    """
    mutable_data = bytearray(data)
    data_length = len(mutable_data)
    
    for _ in range(error_count):
        # 随机选择字节位置
        byte_pos = random.randint(0, data_length - 1)
        # 随机选择bit位(0-7)
        bit_pos = random.randint(0, 7)
        # 使用异或运算翻转bit
        mutable_data[byte_pos] ^= (1 << bit_pos)
    
    return bytes(mutable_data)


def frame_gen(frame_number):
    '''
    generate frame data
    '''
    # if TARGET_IP == '127.0.0.1':
    #     # sim wrong situations
    #     frame_number=gen_wrong_frame(frame_number)
    
    # frame number(4 Bytes)
    seq_bytes = struct.pack("<I",frame_number)
    # timestamp(in ms)(8 Bytes)
    timestamp = int(time.time() * 1000)
    ts_bytes = struct.pack("<Q",timestamp)
    # data 0-255（1266Bytes）
    redund_data = bytes([(i*255)//REDUNDANT_DATA_LEN for i in range(REDUNDANT_DATA_LEN)])
    # complete frame data
    frame_data = seq_bytes + ts_bytes + redund_data

    # sim wrong situations
    if TARGET_IP == '127.0.0.1':
        frame_data = introduce_single_bit_errors(frame_data,1)

    return frame_data
    


if __name__ == "__main__":
    #calculate the interval(in ms)
    interval = calculate_send_interval(UDP_SEND_RATE,1278)  # 1278=4+8+1266

    # sock init
    sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    # bind local IP
    # sock.bind((LOCAL_IP, LOCAL_PORT))

    sock.setsockopt(socket.SOL_SOCKET, 25, b'enx00e04c6800ea' + b'\0')
    # sock.setsockopt(socket.SOL_SOCKET, 25, b'enp46s0' + b'\0')
    
    try:
        tot_start_time = time.perf_counter()
        for i in range(SEND_SUM):
            start_time = time.perf_counter()
            
            frame_to_send = frame_gen(i)
            sock.sendto(frame_to_send,(TARGET_IP,TARGET_PORT))

            end_time = (time.perf_counter() - start_time)*1000
            sleep_time = max(0, (interval - end_time) / 1000)  # 剩余等待时间
            
            if i%100 == 0:
                print(f"send sum:{i}")
                print(f"sleep_time:{sleep_time}")
            
            time.sleep(sleep_time)  # 精确到微秒级等待 
        tot_end_time = time.perf_counter()
        print(f"total exp time:{tot_end_time-tot_start_time}")
            
    except KeyboardInterrupt:
        print("udp send stopped")
    finally:
        sock.close()